﻿using CBS.Common.Web;
using CBS.DB.CBSEntity;
using CBS.Model.ManageModel;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using MySqlConnector;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CBS.DB
{
    /// <summary>
    /// 仓储实现
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public class RepositoryBase<TEntity> : IRepositoryBase<TEntity> where TEntity : class, new()
    {
        private readonly CBSContext dbcontext = new();
        public int SubmitForm(TEntity entity, Expression<Func<TEntity, bool>> predicate = null)
        {
            int re = 0;
            if (predicate != null)
            {
            }
            return re;
        }
        public int Insert(TEntity entity)
        {
            dbcontext.Entry<TEntity>(entity).State = EntityState.Added;
            return dbcontext.SaveChanges();
        }
        public int Insert(List<TEntity> entitys)
        {
            foreach (var entity in entitys)
            {
                dbcontext.Entry<TEntity>(entity).State = EntityState.Added;
            }
            return dbcontext.SaveChanges();
        }

        public static bool SqlBulkCopyByDatatable(DbContext context, IDbContextTransaction transaction, string TableName, DataTable dt)
        {
            try
            {
                // 获取 DbContext 的数据库连接
                var connection = (MySqlConnection)context.Database.GetDbConnection();
                connection.Open();

                // 使用 MySqlBulkCopy 执行批量插入
                var bulkCopy = new MySqlBulkCopy(connection, transaction.GetDbTransaction() as MySqlTransaction);

                bulkCopy.DestinationTableName = TableName;
                bulkCopy.ColumnMappings.AddRange(dt.Columns.Cast<DataColumn>().Select(colum => new MySqlBulkCopyColumnMapping { DestinationColumn = colum.ColumnName, SourceOrdinal = colum.Ordinal }).ToList());
                var result = bulkCopy.WriteToServer(dt);

                // check for problems
                if (result.Warnings.Count != 0) 
                {
                    /* handle potential data loss warnings */
                    return false;
                }

                return true;
            }
            catch (System.Exception ex)
            {

                throw;
            }
        }

        /// <summary>
        /// 更新方法
        /// </summary>
        /// <param name="entity">要更新的实体</param>
        /// <param name="keys">标的所有主键列名数组</param>
        /// <returns></returns>
        public int Update(TEntity entity, List<String> keys)
        {
            dbcontext.Set<TEntity>().Attach(entity);
            PropertyInfo[] props = entity.GetType().GetProperties();
            //List<PropertyInfo> pkProp = typeof(TEntity).GetProperties().ToList();
            //pkProp= pkProp.Where(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Length > 0).ToList();
            foreach (PropertyInfo prop in props)
            {
                if (ExcludeType.IsExclude(prop) && !keys.Contains(prop.Name))
                {
                    if (prop.GetValue(entity, null) != null)
                    {
                        if (prop.GetValue(entity, null).ToString() == "&nbsp;")
                            dbcontext.Entry(entity).Property(prop.Name).CurrentValue = null;
                        dbcontext.Entry(entity).Property(prop.Name).IsModified = true;
                    }
                    else
                    {
                        dbcontext.Entry(entity).Property(prop.Name).IsModified = true;
                    }
                }
            }
            return dbcontext.SaveChanges();
        }
        //public int Update(List<TEntity> entity)
        //{
        //    if (entity == null || entity.Count < 1)
        //    {
        //        throw new ArgumentNullException();
        //    }

        //    entity.ForEach(item => dbcontext.Set<TEntity>().Attach(item));
        //    PropertyInfo pkProp = typeof(TEntity).GetProperties().Where(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Length > 0).FirstOrDefault();
        //    foreach (var item in entity)
        //    {
        //        PropertyInfo[] props = item.GetType().GetProperties();
        //        foreach (PropertyInfo prop in props)
        //        {
        //            if (ExcludeType.IsExclude(prop) && prop != pkProp)
        //            {
        //                if (prop.GetValue(item, null) != null)
        //                {
        //                    if (prop.GetValue(item, null).ToString() == "&nbsp;")
        //                        dbcontext.Entry(item).Property(prop.Name).CurrentValue = null;
        //                    dbcontext.Entry(item).Property(prop.Name).IsModified = true;
        //                }
        //                else
        //                {
        //                    dbcontext.Entry(item).Property(prop.Name).IsModified = true;
        //                }
        //            }
        //        }
        //    }
        //    return dbcontext.SaveChanges();
        //}
        //public int Update<PEntity>(PEntity entity)
        //{
        //    var model = DTOHelper<PEntity, TEntity>.Trans(entity);
        //    return Update(model);
        //}
        public int Delete(TEntity entity)
        {
            dbcontext.Set<TEntity>().Attach(entity);
            dbcontext.Entry<TEntity>(entity).State = EntityState.Deleted;
            return dbcontext.SaveChanges();
        }
        public int Delete(Expression<Func<TEntity, bool>> predicate)
        {
            var entitys = dbcontext.Set<TEntity>().Where(predicate);
            foreach (var item in entitys)
            {
                dbcontext.Entry<TEntity>(item).State = EntityState.Deleted;
            }
            return dbcontext.SaveChanges();
        }
        public TEntity FindEntity(object keyValue)
        {
            return dbcontext.Set<TEntity>().Find(keyValue);
        }
        public TEntity FindEntity(Expression<Func<TEntity, bool>> predicate)
        {
            return dbcontext.Set<TEntity>().FirstOrDefault(predicate);
        }
        public IQueryable<TEntity> IQueryable()
        {
            return dbcontext.Set<TEntity>();
        }
        public IQueryable<TEntity> IQueryable(Expression<Func<TEntity, bool>> predicate)
        {
            return dbcontext.Set<TEntity>().Where(predicate);
        }
        //public List<TEntity> FindList(string strSql)
        //{
        //    FormattableString str = 
        //    return dbcontext.Database.SqlQuery<TEntity>(strSql);
        //}
        public List<TEntity> FindList(Pagination pagination)
        {
            bool isAsc = pagination.sord.ToLower() == "asc";
            string[] _order = pagination.sidx.Split(',');
            var tempData = dbcontext.Set<TEntity>().AsQueryable();
            bool isFirst = true;
            foreach (string item in _order)
            {
                string _orderPart = item;
                _orderPart = Regex.Replace(_orderPart, @"\s+", " ");
                string[] _orderArry = _orderPart.Split(' ');
                string _orderField = _orderArry[0];
                bool sort = isAsc;
                if (_orderArry.Length == 2)
                {
                    isAsc = _orderArry[1].ToUpper() == "ASC" ? true : false;
                }
                var parameter = Expression.Parameter(typeof(TEntity), "t");
                var property = typeof(TEntity).GetProperty(_orderField);
                var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                var orderByExp = Expression.Lambda(propertyAccess, parameter);
                MethodCallExpression resultExp;
                if (isFirst)
                {
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", [typeof(TEntity), property.PropertyType], tempData.Expression, Expression.Quote(orderByExp));
                    tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
                    isFirst = false;
                }
                else
                {
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "ThenBy" : "ThenByDescending", [typeof(TEntity), property.PropertyType], tempData.Expression, Expression.Quote(orderByExp));
                    tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
                }

            }

            pagination.records = tempData.Count();
            tempData = tempData.Skip<TEntity>(pagination.rows * (pagination.page - 1)).Take<TEntity>(pagination.rows).AsQueryable();
            return [.. tempData];
        }
        public List<TEntity> FindList(Expression<Func<TEntity, bool>> predicate, Pagination pagination)
        {
            bool isAsc = pagination.sord.ToLower() == "asc";
            string[] _order = pagination.sidx.Split(',');
            var tempData = dbcontext.Set<TEntity>().Where(predicate);
            bool isFirst = true;
            foreach (string item in _order)
            {
                string _orderPart = item;
                _orderPart = Regex.Replace(_orderPart, @"\s+", " ");
                string[] _orderArry = _orderPart.Split(' ');
                string _orderField = _orderArry[0];
                bool sort = isAsc;
                if (_orderArry.Length == 2)
                {
                    isAsc = _orderArry[1].ToUpper() == "ASC";
                }
                var parameter = Expression.Parameter(typeof(TEntity), "t");
                var property = typeof(TEntity).GetProperty(_orderField);
                var propertyAccess = Expression.MakeMemberAccess(parameter, property);
                var orderByExp = Expression.Lambda(propertyAccess, parameter);

                MethodCallExpression resultExp;
                if (isFirst)
                {
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "OrderBy" : "OrderByDescending", [typeof(TEntity), property.PropertyType], tempData.Expression, Expression.Quote(orderByExp));
                    tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
                    isFirst = false;
                }
                else
                {
                    resultExp = Expression.Call(typeof(Queryable), isAsc ? "ThenBy" : "ThenByDescending", [typeof(TEntity), property.PropertyType], tempData.Expression, Expression.Quote(orderByExp));
                    tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
                }
            }
            //tempData = tempData.Provider.CreateQuery<TEntity>(resultExp);
            pagination.records = tempData.Count();
            tempData = tempData.Skip<TEntity>(pagination.rows * (pagination.page - 1)).Take<TEntity>(pagination.rows).AsQueryable();
            return [.. tempData];
        }
        public bool Exists(Expression<Func<TEntity, bool>> predicate)
        {
            return dbcontext.Set<TEntity>().AsNoTracking().Any(predicate);
        }
    }
}
